package com.imooc.spring.classone;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
 * 被依赖的bean必须优先注册到Ioc容器的
 */
public class ZhuLi {

    private final Map<Class<?>, Object> beans = new HashMap<Class<?>, Object>();

    public void register(Class<?> clazz) throws IllegalAccessException, InvocationTargetException, InstantiationException {
        Object bean = null;

        Constructor<?>[] constructors = clazz.getConstructors();
        for (Constructor<?> constructor : constructors) {
            Class<?>[] paramTypes = constructor.getParameterTypes();
            if (paramTypes.length == 0) {
                bean = constructor.newInstance();
            } else {
                boolean findAllParams = true;
                Object[] paramValues = new Object[paramTypes.length];
                for (int i = 0; i < paramTypes.length; i++) {
                    Class<?> paramType = paramTypes[i];
                    Object paramValue = getBean(paramType);
                    if (paramValue != null) {
                        paramValues[i] = paramValue;
                    } else {
                        findAllParams = false;
                        break;
                    }
                }
                if (findAllParams) {
                    bean = constructor.newInstance(paramValues);
                }
            }
        }

        if (bean == null) {
            throw new RuntimeException("Can't find validate constructor for " + clazz.getName());
        }
        beans.put(clazz, bean);
    }

    public <T> T getBean(Class<T> clazz) {
        if (beans.containsKey(clazz)) {
            return (T) beans.get(clazz);
        } else {
            List<T> ts = new ArrayList<T>();
            for (Class<?> key : beans.keySet()) {
                if (clazz.isAssignableFrom(key)) {
                    ts.add((T) beans.get(key));
                }
            }
            if (ts.size() == 0) {
                return null;
            } else {
                return ts.get(new Random().nextInt(ts.size()));
            }
        }
    }

}
